package com.lottery.game.core.modules.service.app;

import com.lottery.game.common.constants.GameConstants;
import com.lottery.game.common.constants.GlobalLotteryConstants;
import com.lottery.game.common.utils.UUIDUtils;
import com.lottery.game.common.utils.ValidateUtils;
import com.lottery.game.core.modules.entity.app.AddBetRequest;
import com.lottery.game.core.modules.entity.game.GameRoom;
import com.lottery.game.core.modules.entity.user.BetLimit;
import com.lottery.game.core.modules.entity.user.GameBets;
import com.lottery.game.core.modules.entity.user.GameIssue;
import com.lottery.game.core.modules.entity.user.UserBlncDetail;
import com.lottery.game.core.modules.mapper.BetDao;
import com.lottery.game.core.modules.mapper.GameBetsDao;
import com.lottery.game.core.modules.mapper.RoomDao;
import com.lottery.game.core.utils.BetUtils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 游戏下注
 * @author zhuiyv
 * @version 2018-06-17
 */
@Service
public class GameBetService {

	@Autowired
	private GameBetsDao gameBetsDao;

	@Autowired
	private BetDao betDao;

	@Autowired
	private RoomDao roomDao;

    @Transactional
	public int addGameBets(AddBetRequest tmpGameBets,String userId) throws Exception {

	    //检查余额
        BigDecimal beforBlnc = this.betDao.queryUserMoney(userId);
        if(beforBlnc.compareTo(tmpGameBets.getTotleAmt()) <0) {
            //throw new BaseException(500,"余额不足！");
			return -1;
        }
	    //循环betStr 转换为多个gameBets下注
		List<String> betStrList = tmpGameBets.getBetList();
	    //每一注的金额
		List<BigDecimal> pointList = tmpGameBets.getPointList();
		List<Map<String,Object>> betList = new ArrayList<Map<String,Object>>();
	    List<String> idList = new ArrayList<>();
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Calendar calendar = Calendar.getInstance(Locale.CHINESE);
		for (int i = 0; i < betStrList.size(); i++) {
			GameBets gameBets = new GameBets();
			String id = UUIDUtils.randomUUID();
			gameBets.setId(id);
			gameBets.setDelFlag(GameConstants.Str_ZERO);
			gameBets.setBetStr(betStrList.get(i));
			gameBets.setRoomId(tmpGameBets.getRoomId());
			gameBets.setGameId(tmpGameBets.getGameId());
			gameBets.setGameIssue(tmpGameBets.getGameIssue());
			gameBets.setGameUserId(userId);
			gameBets.setPoint(pointList.get(i));
			gameBets.setTotleAmt(pointList.get(i));
			calendar.add(Calendar.SECOND,3);
			String format = simpleDateFormat.format(calendar.getTime());
			gameBets.setCreateDate(format);
			gameBets.setDelFlag("0");
			//检查限额
			checkLimit(gameBets);
			Map<String, Object> map = transformGameBet(gameBets);
			//记录ID,方便账变明细表新增
			idList.add(id);
			betList.add(map);
			//this.gameBetsDao.addGameBets(gameBets);
		}
	    //批量加入
		this.gameBetsDao.addBatchGameBetsByMap(betList);

        GameIssue queryGame = new GameIssue();
        queryGame.setId(tmpGameBets.getGameId());
		GameRoom room = this.roomDao.queryRoomByRoomNo(tmpGameBets.getRoomId());
		List<GameIssue> gameList = this.betDao.queryGameIssue(queryGame);
        //用户余额记录同步操作
		Date date = new Date();
		String format = simpleDateFormat.format(date);
		List<UserBlncDetail> userBlncDetailList = new ArrayList<>();
		for (int i = 0; i < idList.size(); i++) {
			BigDecimal pointMoney = BigDecimal.ZERO.subtract(pointList.get(i)).setScale(2);
			UserBlncDetail userBlncDetail = new UserBlncDetail();
			userBlncDetail.setId(UUIDUtils.randomUUID());
			userBlncDetail.setGameId(tmpGameBets.getGameId());
			userBlncDetail.setBetType(GameConstants.BlanceChangeType_Bet);
			userBlncDetail.setUserId(userId);
			userBlncDetail.setChange(String.valueOf(pointList.get(i)));
			userBlncDetail.setChangeAmt(pointMoney);
			userBlncDetail.setBeforBlnc(beforBlnc);
			//减去
			beforBlnc = beforBlnc.add(pointMoney);
			userBlncDetail.setResultBlnc(beforBlnc);
			//账变原因
			StringBuffer sb = new StringBuffer();
			if(room!=null) {
				sb.append(room.getName());
			}
			if(gameList!=null&&gameList.size()>0) {
				sb.append("第");
				sb.append(gameList.get(0).getIssueApi());
				sb.append("期");
				sb.append("下注[");
				sb.append(betStrList.get(i));
				sb.append("|");
				sb.append(pointList.get(i));
				sb.append("]");
			}
			String changeReason = sb.toString();
			userBlncDetail.setChangeReason(changeReason);
			userBlncDetail.setGameBetId(idList.get(i));
			userBlncDetail.setChangeTime(format);
			userBlncDetailList.add(userBlncDetail);
			this.betDao.addBalanceDetail(userBlncDetail);
			TimeUnit.MILLISECONDS.sleep(100);
		}

		//this.betDao.insertBalanceDetailByList(userBlncDetailList);
        this.betDao.subUserMoney(tmpGameBets.getTotleAmt(), userId);
        return 0;
	}

	public static void main(String[] args) throws InterruptedException {
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Calendar calendar = Calendar.getInstance(Locale.CHINESE);
		for (int i=0;i<30;i++){
			String format = simpleDateFormat.format(new Date());
			System.out.println(format);
		}

	}
	/**
	 * 检查余额限制
	 * @param gameBets
	 * @throws Exception
	 */
	private void checkLimit(GameBets gameBets) throws Exception {
	    String roomNumber = gameBets.getRoomId();
	    String gameId = gameBets.getGameId();
	    String userId = gameBets.getGameUserId();
	    String betStr = gameBets.getBetStr();
	    BigDecimal point = gameBets.getPoint();
	    BigDecimal currentTotleAmt = gameBets.getTotleAmt();
	    //拆分处理，为了兼容一次多项选择下注
	    String[] splitBetArr = betStr.split(",");
	    List<BetLimit> limitList = this.betDao.queryLimitByRoomNumber(roomNumber);
	    if(limitList!=null&&limitList.size()>0) {
	        BetLimit limitInfo = limitList.get(0);
	        BigDecimal totleAmt = this.betDao.queryCurrentIssueBetTotleAmt(gameId, userId);
	        totleAmt = ValidateUtils.dealNULL(totleAmt);
	        if(currentTotleAmt.add(totleAmt).compareTo(new BigDecimal(limitInfo.getTotalQuota()))>0) {
	            throw new Exception("超出房间下注总额,限额:"+limitInfo.getTotalQuota());
	        }
	        for(String tmpBetStr:splitBetArr) {
	            BigDecimal typeAmt = this.betDao.queryCurrentIssueTypeBetAmt(gameId, userId, tmpBetStr);
	            typeAmt = ValidateUtils.dealNULL(typeAmt);
	            Integer limitMaxAmt = BetUtils.getMaxAmtByBetStr(limitInfo, tmpBetStr);
	            Integer limitMinAmt = BetUtils.getMinAmtByBetStr(limitInfo, tmpBetStr);
	            if(limitMaxAmt!=null&&point.add(typeAmt).compareTo(new BigDecimal(limitMaxAmt))>0) {
	                throw new Exception("当前类型下注超出最高限额,限额:"+limitMaxAmt);
	            }
	            if(limitMinAmt!=null&&point.compareTo(new BigDecimal(limitMinAmt))<0) {
	                throw new Exception("当前类型下注低于最低限额,限额:"+limitMinAmt);
	            }
	        }
	    }
    }

    public List<GameBets> queryGameBets(GameBets gameBets){
		return  this.gameBetsDao.queryGameBets(gameBets);
	}

	public List<GameBets> queryGameBetsForRoom(String userId,String roomId,String gameId,int start,int size,String startDate,String endDate){
        return  this.gameBetsDao.queryGameBetsForRoom(userId, roomId, gameId, start, size,startDate,endDate);
    }

	/**
	 * 获取用户合计数据
	 * @param userId
	 */
	public Map<String, Object> queryUserBetSum(String userId,String roomNumber,String startDate,String endDate) {
	    Map<String, Object>  map = this.gameBetsDao.queryUserBetSum(userId, roomNumber,startDate,endDate);
	    return map;
	}


	public void updateGameBets(GameBets gameBets){
		this.gameBetsDao.updateGameBets(gameBets);
	}
	/**
	 * 删除需要确定是在封盘前状态，
	 * 且反写用户金额，和用户余额明细表
	 * @author zhuiyv
	 * @date 2018-06-23
	 * @param gameBets
	 * @throws Exception
	 */
//	@Transactional
	public int deleteGameBets(GameBets gameBets) {

		List<GameBets> gameBetList = this.gameBetsDao.queryGameBets(gameBets);
		if(gameBetList.size()!=1){
			//throw new Exception("下注信息获取异常，只能取消一条");
			return GlobalLotteryConstants.RES_ERROR_TWO;
		}
		GameBets bet = gameBetList.get(0);
		int num = this.gameBetsDao.deleteGameBets(bet);
		if(num==1){

		    StringBuffer sb = new StringBuffer();
	        GameRoom room = this.roomDao.queryRoomByRoomNo(bet.getRoomId());
	        if(room!=null&&room.getName()!=null) {
	            //游戏类型
	            sb.append(room.getName());
	        }

	        GameIssue queryGame = new GameIssue();
	        queryGame.setId(bet.getGameId());
	        List<GameIssue> gameList = this.betDao.queryGameIssue(queryGame );
	        if(gameList!=null&&gameList.size()>0) {
	            sb.append("第");
	            sb.append(gameList.get(0).getIssueApi());
	            sb.append("期");
	        }

	        sb.append("取消下注[");
	        sb.append(bet.getBetStr());
            sb.append("|");
            sb.append(bet.getTotleAmt());
	        sb.append("]");

	        String changeReason = sb.toString();

			BigDecimal changeMoney = bet.getTotleAmt().setScale(2);
			BigDecimal beforBlnc = this.betDao.queryUserMoney(bet.getGameUserId());
			UserBlncDetail userBlncDetail = new UserBlncDetail();
			userBlncDetail.setId(UUIDUtils.randomUUID());
			userBlncDetail.setGameId(bet.getGameId());
			userBlncDetail.setUserId(bet.getGameUserId());
			userBlncDetail.setBetType(GameConstants.BlanceChangeType_CancelBet);
			userBlncDetail.setChange(String.valueOf(bet.getTotleAmt()));
			userBlncDetail.setChangeAmt(changeMoney);
			userBlncDetail.setBeforBlnc(beforBlnc);
			userBlncDetail.setGameBetId(bet.getId());
			userBlncDetail.setResultBlnc(beforBlnc.add(changeMoney));
			userBlncDetail.setChangeReason(changeReason);
			this.betDao.addBalanceDetail(userBlncDetail);
			this.betDao.addUserMoney(changeMoney, bet.getGameUserId());
		}else{
			if(GameConstants.Str_ZERO.equals(bet.getDelFlag())){
				//throw new Exception("已取消下注，请不要重复操作");
				return GlobalLotteryConstants.RES_ERROR;
			}
		}
		return num;
	}

	public int batchDeleteGameBets(GameBets gameBets, List<String> gameBetIdList) {

		List<GameBets> gameBetList = this.gameBetsDao.batchQueryGameBets(gameBets, gameBetIdList);
		GameBets bet = gameBetList.get(0);
		int num = this.gameBetsDao.batchDeleteGameBets(bet, gameBetIdList);
		if(num > 0){

			StringBuffer sb = new StringBuffer();
			GameRoom room = this.roomDao.queryRoomByRoomNo(bet.getRoomId());
			if(room!=null&&room.getName()!=null) {
				//游戏类型
				sb.append(room.getName());
			}

			GameIssue queryGame = new GameIssue();
			queryGame.setId(bet.getGameId());
			List<GameIssue> gameList = this.betDao.queryGameIssue(queryGame );
			if(gameList!=null&&gameList.size()>0) {
				sb.append("第");
				sb.append(gameList.get(0).getIssueApi());
				sb.append("期");
			}

			sb.append("取消下注[");
			sb.append(bet.getBetStr());
			sb.append("|");
			sb.append(bet.getTotleAmt());
			sb.append("]");

			String changeReason = sb.toString();

			BigDecimal changeMoney = bet.getTotleAmt().setScale(2);
			BigDecimal beforBlnc = this.betDao.queryUserMoney(bet.getGameUserId());
			UserBlncDetail userBlncDetail = new UserBlncDetail();
			userBlncDetail.setId(UUIDUtils.randomUUID());
			userBlncDetail.setGameId(bet.getGameId());
			userBlncDetail.setUserId(bet.getGameUserId());
			userBlncDetail.setBetType(GameConstants.BlanceChangeType_CancelBet);
			userBlncDetail.setChange(String.valueOf(bet.getTotleAmt()));
			userBlncDetail.setChangeAmt(changeMoney);
			userBlncDetail.setBeforBlnc(beforBlnc);
			userBlncDetail.setResultBlnc(beforBlnc.add(changeMoney));
			userBlncDetail.setChangeReason(changeReason);
			this.betDao.addBalanceDetail(userBlncDetail);
			this.betDao.addUserMoney(changeMoney, bet.getGameUserId());
		}else{
			if(GameConstants.Str_ZERO.equals(bet.getDelFlag())){
				//throw new Exception("已取消下注，请不要重复操作");
				return GlobalLotteryConstants.RES_ERROR;
			}
		}
		return num;
	}

	/**
	 * 将前端数据转换为map数据
	 * @param gameBets
	 * @return
	 */
	private Map<String, Object> transformGameBet(GameBets gameBets){
	    Map<String, Object> map = new HashMap<>();
	    //基本信息
	    map.put("id", gameBets.getId());
	    map.put("totleAmt", gameBets.getTotleAmt());
	    map.put("point", gameBets.getPoint());
	    map.put("delFlag", "0");
        map.put("gameUserId", gameBets.getGameUserId());
        map.put("gameId", gameBets.getGameId());
        map.put("roomId", gameBets.getRoomId());
		map.put("betStr", gameBets.getBetStr());

		map.put("createDate", gameBets.getCreateDate());
		map.put("updateDate", gameBets.getCreateDate());



		String betStr = gameBets.getBetStr();
        String[] strArr = betStr.split(",");
        for(String item:strArr){
            map.put(item, 1);
        }
	    return map;
	}

	public List<GameBets> queryGameBetsForRoomByTickType(String userId,String startDate,String endDate,
											   String gameTypePlayingTicket,String status,String betType) {
		return this.gameBetsDao.queryGameBetsForRoomByTickType(userId,startDate,endDate,gameTypePlayingTicket,status,betType);
	}

	public List<GameBets> queryGameBetsForRoomByTickTypeLast(String userId,String startDate,String endDate,
														 String gameTypePlayingTicket,String status,String betType) {
		return this.gameBetsDao.queryGameBetsForRoomByTickTypeLast(userId,startDate,endDate,gameTypePlayingTicket,status);
	}

}
